package logic

import (
	"context"
	"crypto/rand"
	"errors"
	"fmt"
	"godco/internal/utils"
	"math/big"
	"strconv"
	"strings"
	"time"

	u "godco/internal/model/users"
	"godco/internal/svc"
	"godco/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserSignLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserSignLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserSignLogic {
	return &UserSignLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserSignLogic) UserSign(req *types.SignRequest) (resp *types.SignResp, err error) {
	// todo: add your logic here and delete this line
	//先验证验证码是否正确
	key := req.Email
	value, err := l.svcCtx.RedisClient.Get(key)
	if err != nil {
		return nil, err
	}
	if value != req.VerifyCode {
		return nil, errors.New("验证码错误")
	}
	l.svcCtx.RedisClient.Del(key)

	_, err = l.svcCtx.AuthModel.FindOneByInstallID(l.ctx, strconv.FormatInt(req.Aid, 10))
	if err == u.ErrNotFound {
		return nil, errors.New("请获取正确的签署地址")
	}

	user, err := l.svcCtx.UserModel.FindOneByEmailAndInstallationId(l.ctx, req.Email, req.Aid)
	if err == u.ErrNotFound {
		data := u.User{Name: req.Name, Email: req.Email, SignStatus: 1, State: "yes", InstallationId: req.Aid, CreateAt: time.Now()}
		err = l.svcCtx.UserModel.Insert(l.ctx, &data)
		if err != nil {
			resp = &types.SignResp{
				Code:    403,
				Message: err.Error(),
			}
			return resp, nil
		}
	} else {
		if user.SignStatus == 2 {
			user.SignStatus = 1
			user.CreateAt = time.Now()
			l.svcCtx.UserModel.Update(l.ctx, user)
		}

	}
	resp = &types.SignResp{
		Code:    0,
		Message: "success",
	}
	return resp, nil
}

func (l *UserSignLogic) CaptureEmailCode(req *types.EmailCodRequest) (resp *types.EmailCodeResp, err error) {
	user, _ := l.svcCtx.UserModel.FindOneByEmailAndInstallationId(l.ctx, req.Email, req.Aid)
	if user != nil && user.SignStatus == 1 {
		return nil, errors.New("该邮箱已签署")
	}
	key := req.Email
	keyBool, err := l.svcCtx.RedisClient.Exists(key)
	if err != nil {
		return nil, err
	}
	if keyBool {
		return nil, errors.New("操作频繁")
	}
	//获取当前时间戳的毫秒数
	timestamp := time.Now().UnixMilli()
	// 结合时间戳和随机数生成唯一种子
	// 这里将时间戳作为随机数生成的一部分，确保每次生成的验证码和时间相关
	seed := fmt.Sprintf("%d", timestamp)

	// 生成随机数
	var code string
	for i := 0; i < 6; i++ {
		// 生成 0 到 9 之间的随机数
		n, _ := rand.Int(rand.Reader, big.NewInt(10))
		// 将随机数添加到验证码中
		code += fmt.Sprintf("%d", n.Int64())
	}

	// 可以根据需要对验证码进行哈希处理或其他操作，进一步保证唯一性
	// 这里简单地将时间戳的后几位和随机验证码拼接
	uniqueCode := fmt.Sprintf("%s%s", seed[len(seed)-3:], code)
	uniqueCode = uniqueCode[len(uniqueCode)-6:]
	resp = &types.EmailCodeResp{
		Code:    0,
		Message: "success",
	}
	err = l.svcCtx.RedisClient.Setex(key, code, 600)
	if err != nil {
		return nil, err
	}
	emailTemplateContent, _ := utils.ReadTemplateFile("email_verify_code_template.txt")
	if emailTemplateContent == "" {
		emailTemplateContent = l.svcCtx.Config.EConf.EmailCodeInfo
	}
	l.Debug(uniqueCode)
	emailContent := strings.Replace(emailTemplateContent, "{verifyCode}", uniqueCode, -1)

	err = utils.SendEmail(l.svcCtx.Config.EConf.From, l.svcCtx.Config.EConf.Pwd, l.svcCtx.Config.EConf.Server, req.Email, "DCO签名验证码", emailContent, "text/html")
	if err != nil {
		l.svcCtx.RedisClient.Del(key)
		return nil, err
	}
	return resp, nil
}

func (l *UserSignLogic) UserSignedPage(req *types.UserSignedPageRequest) (resp *types.UserSignedPageResponse, err error) {
	skip := (req.PageNum - 1) * req.PageSize
	limit := req.PageSize
	usersignlist, count, err := l.svcCtx.UserModel.FindByEmailPage(l.ctx, req.Email, skip, limit)
	if err != nil {
		return nil, err
	}
	var list = make([]types.UserSignedResponse, 0)
	for _, v := range usersignlist {
		//查询 应用信息
		installApp, err := l.svcCtx.AuthModel.FindOneByInstallID(l.ctx, strconv.FormatInt(v.InstallationId, 10))
		if err != nil {
			continue
		}

		vo := types.UserSignedResponse{
			InstallationId: v.InstallationId,
			Email:          v.Email,
			Name:           v.Name,
			TargetId:       installApp.TargetId,
			TargetName:     installApp.TargetName,
			TargetUrl:      l.svcCtx.Config.ApplicationConf.AtomgitHost + "/" + installApp.TargetName,
			TargetType:     installApp.TargetType,
			SignStatus:     v.SignStatus,
			SignTime:       v.CreateAt.Format("20060102 15:04:05"),
		}

		if v.SignStatus == 2 {
			vo.RevokeTime = v.UpdateAt.Format("2006-01-02 15:04:05")
		}
		list = append(list, vo)
	}
	return &types.UserSignedPageResponse{
		Content:  list,
		Total:    count,
		PageNum:  req.PageNum,
		PageSize: req.PageSize,
		Code:     200,
		Msg:      "success",
	}, nil
}

func (l *UserSignLogic) SignedUserPage(req *types.SignedUserPageRequest) (resp *types.SignedUserPageResponse, err error) {
	skip := (req.PageNum - 1) * req.PageSize
	limit := req.PageSize
	installId, _ := strconv.ParseInt(req.InstallationId, 10, 64)
	param := u.User{
		SignStatus:     req.SignStatus,
		InstallationId: installId,
	}
	usersignlist, count, err := l.svcCtx.UserModel.FindByInstallIdPage(l.ctx, param, skip, limit)
	if err != nil {
		return nil, err
	}
	auth, _ := l.svcCtx.AuthModel.FindOneByInstallID(l.ctx, req.InstallationId)
	var list = make([]types.SignedUserResponse, 0)
	for _, v := range usersignlist {
		vo := types.SignedUserResponse{
			InstallationId: v.InstallationId,
			Email:          v.Email,
			Name:           v.Name,
			SignStatus:     v.SignStatus,
			SignTime:       v.CreateAt.Format("20060102 15:04:05"),
		}

		if v.SignStatus == 2 {
			vo.RevokeTime = v.UpdateAt.Format("2006-01-02 15:04:05")
		}

		if auth != nil {
			vo.TargetId = auth.TargetId
			vo.TargetName = auth.TargetName
			vo.TargetUrl = l.svcCtx.Config.ApplicationConf.AtomgitHost + "/" + auth.TargetName
			vo.TargetType = auth.TargetType
		}
		list = append(list, vo)
	}
	return &types.SignedUserPageResponse{
		Content:  list,
		Total:    count,
		PageNum:  req.PageNum,
		PageSize: req.PageSize,
		Code:     200,
		Msg:      "success",
	}, nil
}

func (l *UserSignLogic) UserCancelSign(req *types.UserCancelSignRequest) (err error) {
	info, err := l.svcCtx.UserModel.FindOneByEmailAndInstallationId(l.ctx, req.Email, req.InstallationId)
	if err == nil {
		info.SignStatus = 2
		info.UpdateAt = time.Now()
		l.svcCtx.UserModel.Update(l.ctx, info)
	}
	return nil
}

func (l *UserSignLogic) SignedUserDetail(req *types.SignedUserDetailRequest) (*types.SignedDetailResponse, error) {
	//_, err := l.svcCtx.AuthModel.FindByTargetIdAndInstallID(l.ctx, req.TargetId, strconv.FormatInt(req.InstallationId, 10))
	//if err != nil {
	//	return nil, err
	//}
	info, err := l.svcCtx.UserModel.FindOneByEmailAndInstallationId(l.ctx, req.Email, req.InstallationId)
	if err != nil {
		return nil, err
	}
	auth, _ := l.svcCtx.AuthModel.FindOneByInstallID(l.ctx, strconv.FormatInt(req.InstallationId, 10))
	u := &types.SignedDetailResponse{
		Email:      info.Email,
		Name:       info.Name,
		SignStatus: info.SignStatus,
		SignTime:   info.CreateAt.Format("2006-01-02 15:04:05"),
	}
	if info.SignStatus == 2 {
		u.RevokeTime = info.UpdateAt.Format("2006-01-02 15:04:05")
	}

	if auth != nil {
		u.TargetId = auth.TargetId
		u.TargetName = auth.TargetName
		u.TargetUrl = l.svcCtx.Config.ApplicationConf.AtomgitHost + "/" + auth.TargetName
		u.TargetType = auth.TargetType
	}

	content, err := utils.ReadTemplateFile("dco_content_template.txt")
	if err == nil {
		u.Content = content
	}
	return u, nil
}

func (l *UserSignLogic) UserSignedDetail(req *types.UserSignedDetailRequest) (*types.SignedDetailResponse, error) {
	info, err := l.svcCtx.UserModel.FindOneByEmailAndInstallationId(l.ctx, req.Email, req.InstallationId)
	if err != nil {
		return nil, err
	}
	return &types.SignedDetailResponse{
		Email: info.Email,
		Name:  info.Name,
	}, nil
}

func (l *UserSignLogic) SignedListDetail(req *types.SignedUserListRequest) ([]types.SignedUserResponse, error) {
	param := u.User{
		InstallationId: req.InstallationId,
	}
	signList, err := l.svcCtx.UserModel.FindByInstallIdList(l.ctx, param)
	if err != nil {
		return nil, err
	}

	auth, _ := l.svcCtx.AuthModel.FindOneByInstallID(l.ctx, strconv.FormatInt(req.InstallationId, 10))
	var list = make([]types.SignedUserResponse, 0)
	for _, v := range signList {
		vo := types.SignedUserResponse{
			InstallationId: v.InstallationId,
			Email:          v.Email,
			Name:           v.Name,
			SignStatus:     v.SignStatus,
			SignTime:       v.CreateAt.Format("20060102 15:04:05"),
		}

		if v.SignStatus == 2 {
			vo.RevokeTime = v.UpdateAt.Format("2006-01-02 15:04:05")
		}

		if auth != nil {
			vo.TargetId = auth.TargetId
			vo.TargetName = auth.TargetName
			vo.TargetUrl = l.svcCtx.Config.ApplicationConf.AtomgitHost + "/" + auth.TargetName
			vo.TargetType = auth.TargetType
		}
		list = append(list, vo)
	}

	return list, nil
}
